home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 6_2008-2009.ISO / data / zips / jcMDITabs_2151044302009.psc / jcMDItabs v1.2 / jcMDITabs / CEasySubclass_v1.cls next >
Text File  |  2004-11-16  |  14KB  |  316 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "CEasySubclass_v1"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. '*******************************************************************************
  15. '*    Author      : Paul Caton, Vlad Vissoultchev, modified by Andrea Batina[Revelatek]
  16. '*    Date        : 30 July 2004
  17. '*
  18. '*    Component   : CEasySubclass_v1
  19. '*    Description : Module-less, IDE safe, machine code subclassing thunk.
  20. '*
  21. '*    Dependencies: Subclassing/hooking sink interfaces 1.0 TypeLib [SubclassingSink.tlb]
  22. '*
  23. '*    Copyright   : Copyright ⌐ 2004 Revelatek. All rights reserved.
  24. '*------------------------------------------------------------------------------
  25. '*    Portions copyright (c) 2002 by Paul Caton <Paul_Caton@hotmail.com>
  26. '*    Portions copyright (c) 2002 by Vlad Vissoultchev <wqweto@myrealbox.com>
  27. '*******************************************************************************
  28.  
  29. Option Explicit
  30.  
  31. '////////////////////////////////////////////////////////////////////
  32. '// Private/Public Type Definitions
  33. Private Type OSVERSIONINFO
  34.     dwOSVersionInfoSize             As Long
  35.     dwMajorVersion                  As Long
  36.     dwMinorVersion                  As Long
  37.     dwBuildNumber                   As Long
  38.     dwPlatformID                    As Long
  39.     szCSDVersion                    As String * 128
  40. End Type
  41. Private Type UcsData
  42.     hWnd                            As Long
  43.     OrigWndProc                     As Long
  44.     SinkInterface                   As Long
  45.     MsgBuffer                       As Long
  46.     BeforeBufferSize                As Long
  47.     AfterBufferSize                 As Long
  48.     AddrCallWindowProc              As Long
  49.     AddrSetWindowLong               As Long
  50.     AddrEbMode                      As Long
  51.     AddrHeapFree                    As Long
  52.     ProcessHeap                     As Long
  53. End Type
  54. Private Type UcsThunk
  55.     Code(0 To &H190 \ 4 - 1)     As Long
  56.     Data                            As UcsData
  57. End Type
  58.  
  59. '////////////////////////////////////////////////////////////////////
  60. '// Private/Public Win32 API Declarations
  61. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
  62. Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
  63. Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
  64. Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
  65. Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  66. Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  67. Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
  68. Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal lpMem As Long) As Long
  69. Private Declare Function GetProcessHeap Lib "kernel32" () As Long
  70. Private Declare Function IsWindow Lib "user32" (ByVal hWnd As Long) As Long
  71. Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
  72.  
  73. '////////////////////////////////////////////////////////////////////
  74. '// Private/Public Constant Declarations
  75. Private Const VER_PLATFORM_WIN32_NT     As Long = 2
  76.  
  77. Private Const STR_ASM_OPCODES           As String = "&H83EC8B55 &HE860F0C4 &H0 &HCEB815B &H33004010 &HF84589C0 &H8BFC4589 &H4011A08B &HFC98500 &H9684 &HFFF98300 &HBB8B1174 &H40119C &HF20C458B &H80850FAF &H83000000 &H4011B0BB &H36740000 &H11B093FF &HF8830040 &HC72B7502 &H1F845 &H63EB0000 &H1E75C085 &H1194B3FF &HFC6A0040 &H1190B3FF &H93FF0040 &H4011AC &H119883C7 &H40 &H938B0000 &H401198 &H3774D285 &HC085028B &H253174 &H75800000 &H458D532A &H458D5014 &H458D5010 &H458D500C &H458D5008 &H458D50FC &H8B5250F8 &H2050FF02 &HF87D835B &H8B850F00 &H53000000 &HFF1475FF &H75FF1075 " & _
  78.                                                     "&H875FF0C &H1194B3FF &H93FF0040 &H4011A8 &HFC45895B &HF87D83 &H8B8B6875 &H4011A4 &H5E74C985 &H74FFF983 &H9CBB8B16 &H8B004011 &H4011A083 &H873C8D00 &HF20C458B &H834375AF &H4011B0BB &HB740000 &H11B093FF &HF8830040 &H8B2F7402 &H40119893 &H74D28500 &H85028B25 &H251F74C0 &H80000000 &HFF531875 &H75FF1475 &HC75FF10 &H8D0875FF &H5250FC45 &H50FF028B &H7D815B1C &H820C &HC7357500 &H40119083 &H0 &H838D00 &H50004010 &HB3FF006A &H4011B8 &H50F0458D &H1188838B &H45890040 &H8C838BF0 &H89004011 &HA3FFF445 &H4011B4 &HFC458B61 &H10C2C9"
  79. Private Const STR_MODULE_USER32         As String = "user32"
  80. Private Const STR_MODULE_KERNEL32       As String = "kernel32"
  81. Private Const STR_MODULE_VBA6           As String = "vba6"
  82. Private Const STR_MODULE_VBA5           As String = "vba5"
  83. Private Const STR_CALLWINDOWPROC        As String = "CallWindowProcA"
  84. Private Const STR_SETWINDOWLONG         As String = "SetWindowLongA"
  85. Private Const STR_EBMODE                As String = "EbMode"
  86. Private Const STR_HEAPFREE              As String = "HeapFree"
  87.  
  88. '////////////////////////////////////////////////////////////////////
  89. '// Private/Public Variable Declarations
  90. Private m_uThunk                    As UcsThunk
  91. Private m_pThunk                    As Long
  92. Private m_aBeforeMsgs()             As Long
  93. Private m_aAfterMsgs()              As Long
  94. Private m_vTag                      As Variant
  95. Private m_oSinkInterface            As ISubclassingSink
  96. Private m_bDontFree                 As Boolean
  97.  
  98. '//////////////////////////////////////////////////////////////////////////////
  99. '//// PUBLIC PROPERTIES
  100. '//////////////////////////////////////////////////////////////////////////////
  101. Property Get ThunkAddress() As Long
  102.     If m_pThunk = 0 Then m_pThunk = HeapAlloc(GetProcessHeap(), 0, Len(m_uThunk))
  103.     ThunkAddress = m_pThunk
  104. End Property
  105. Property Get Tag() As Variant
  106.     If IsObject(m_vTag) Then
  107.         Set Tag = m_vTag
  108.     Else
  109.         Tag = m_vTag
  110.     End If
  111. End Property
  112. Property Let Tag(vValue As Variant)
  113.     m_vTag = vValue
  114. End Property
  115. Property Set Tag(ByVal oValue As Object)
  116.     Set m_vTag = oValue
  117. End Property
  118. Property Get hWnd() As Long
  119.     hWnd = m_uThunk.Data.hWnd
  120. End Property
  121.  
  122. '//////////////////////////////////////////////////////////////////////////////
  123. '//// PUBLIC METHODS
  124. '//////////////////////////////////////////////////////////////////////////////
  125. Public Function AddBeforeMsgs(ParamArray uMsgs()) As Boolean
  126.     Dim lIdx            As Long
  127.     
  128.     AddBeforeMsgs = True
  129.     For lIdx = 0 To UBound(uMsgs)
  130.         AddBeforeMsgs = AddBeforeMsgs And pvAddMsg(m_aBeforeMsgs, uMsgs(lIdx))
  131.     Next
  132. End Function
  133. Public Function AddAfterMsgs(ParamArray uMsgs()) As Boolean
  134.     Dim lIdx            As Long
  135.     
  136.     AddAfterMsgs = True
  137.     For lIdx = 0 To UBound(uMsgs)
  138.         AddAfterMsgs = AddAfterMsgs And pvAddMsg(m_aAfterMsgs, uMsgs(lIdx))
  139.     Next
  140. End Function
  141. Public Function Subclass(ByVal hWnd As Long, ByVal Sink As ISubclassingSink, Optional ByVal WeakReference As Boolean = False, Optional ByVal DontFree As Boolean = False) As Boolean
  142.     With m_uThunk.Data
  143.         '--- state check
  144.         If .hWnd <> 0 Then
  145.             Exit Function
  146.         End If
  147.         m_bDontFree = DontFree
  148.         '--- store hWnd
  149.         .hWnd = hWnd
  150.         '--- store a reference (AddRef'd)
  151.         If Not WeakReference Then
  152.             Set m_oSinkInterface = Sink
  153.         End If
  154.         CopyMemory VarPtr(.SinkInterface), VarPtr(Sink), 4
  155.         '--- store API functions entry points
  156.         .AddrCallWindowProc = pvGetProcAddr(STR_MODULE_USER32, STR_CALLWINDOWPROC)
  157.         .AddrSetWindowLong = pvGetProcAddr(STR_MODULE_USER32, STR_SETWINDOWLONG)
  158.         '--- first try VBA6.DLL for EbMode function
  159.         .AddrEbMode = pvGetProcAddr(STR_MODULE_VBA6, STR_EBMODE)
  160.         '--- then VBA5.DLL
  161.         If .AddrEbMode = 0 Then
  162.             .AddrEbMode = pvGetProcAddr(STR_MODULE_VBA5, STR_EBMODE)
  163.         End If
  164.         '--- store heap management vars
  165.         .AddrHeapFree = pvGetProcAddr(STR_MODULE_KERNEL32, STR_HEAPFREE)
  166.         .ProcessHeap = GetProcessHeap()
  167.         '--- change wndproc
  168.         .OrigWndProc = SetWindowLong(hWnd, GWL_WNDPROC, ThunkAddress)
  169.     End With
  170.     '--- refresh heap chunk
  171.     CopyMemory ThunkAddress, VarPtr(m_uThunk), Len(m_uThunk)
  172.     '--- success
  173.     Subclass = pvRefreshMsgsBuffer
  174. End Function
  175. Public Function UnSubclass() As Boolean
  176.     Dim hSaveWnd            As Long
  177.     
  178.     With m_uThunk.Data
  179.         ' Double subclass
  180.         Debug.Assert GetWindowLong(.hWnd, GWL_WNDPROC) = 0 Or GetWindowLong(.hWnd, GWL_WNDPROC) = ThunkAddress
  181.         
  182.         '--- state check
  183.         If .hWnd = 0 Then Exit Function
  184.         '--- if stored reference is Release'd
  185.         Set m_oSinkInterface = Nothing
  186.         .SinkInterface = 0
  187.         '--- prevent message buffers being traversed
  188.         .BeforeBufferSize = 0
  189.         .AfterBufferSize = 0
  190.         '--- free previous buffer
  191.         If .MsgBuffer <> 0 Then
  192.             HeapFree GetProcessHeap(), 0, .MsgBuffer
  193.             .MsgBuffer = 0
  194.         End If
  195.         '--- try to unsubclass
  196.         If GetWindowLong(.hWnd, GWL_WNDPROC) = ThunkAddress Then
  197.             SetWindowLong .hWnd, GWL_WNDPROC, .OrigWndProc
  198.             If Not m_bDontFree Then
  199.                 HeapFree GetProcessHeap(), 0, m_pThunk
  200.                 m_pThunk = 0
  201.             End If
  202.         End If
  203.         '--- can call Subclass later yet again
  204.         hSaveWnd = .hWnd
  205.         .hWnd = 0
  206.     End With
  207.     '--- if heap chunk available
  208.     If IsWindow(hSaveWnd) And m_pThunk <> 0 Then
  209.         If m_bDontFree And Not IsNT Then
  210.             m_uThunk.Data.ProcessHeap = 0
  211.         End If
  212.         '--- inactivate heap chunk
  213.         CopyMemory m_pThunk, VarPtr(m_uThunk), Len(m_uThunk)
  214.         m_pThunk = 0
  215.     End If
  216.     '--- success
  217.     UnSubclass = True
  218. End Function
  219. Public Function CallOrigWndProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long)
  220.     If m_uThunk.Data.hWnd <> 0 Then
  221.         CallOrigWndProc = CallWindowProc(m_uThunk.Data.OrigWndProc, m_uThunk.Data.hWnd, uMsg, wParam, lParam)
  222.     End If
  223. End Function
  224.  
  225. '//////////////////////////////////////////////////////////////////////////////
  226. '//// PRIVATE METHODS
  227. '//////////////////////////////////////////////////////////////////////////////
  228. Private Function pvAddMsg(aMsgs() As Long, ByVal uMsg As Long) As Boolean
  229.     '--- if not filtered yet -> append msg
  230.     If pvFindMsg(aMsgs, uMsg) < 0 Then
  231.         '--- resize array
  232.         If UBound(aMsgs) < 0 Then
  233.             ReDim aMsgs(0 To 0)
  234.         Else
  235.             ReDim Preserve aMsgs(0 To UBound(aMsgs) + 1)
  236.         End If
  237.         '--- append new msg
  238.         aMsgs(UBound(aMsgs)) = uMsg
  239.         '--- success (or failure)
  240.         pvAddMsg = pvRefreshMsgsBuffer()
  241.     End If
  242. End Function
  243. Private Function pvFindMsg(aMsgs() As Long, ByVal uMsg As Long)
  244.     Dim lIdx            As Long
  245.     
  246.     pvFindMsg = -1
  247.     For lIdx = 0 To UBound(aMsgs)
  248.         If aMsgs(lIdx) = uMsg Then
  249.             pvFindMsg = lIdx
  250.             Exit Function
  251.         End If
  252.     Next
  253. End Function
  254. Private Function pvRefreshMsgsBuffer() As Boolean
  255.     Dim lBeforeSize     As Long
  256.     Dim lAfterSize      As Long
  257.     
  258.     With m_uThunk.Data
  259.         '--- init local vars
  260.         lBeforeSize = UBound(m_aBeforeMsgs) + 1
  261.         lAfterSize = UBound(m_aAfterMsgs) + 1
  262.         '--- free previous buffer
  263.         If .MsgBuffer <> 0 Then
  264.             HeapFree GetProcessHeap(), 0, .MsgBuffer
  265.             .MsgBuffer = 0
  266.         End If
  267.         '--- if any msg -> allocate new buffer
  268.         If lBeforeSize + lAfterSize > 0 Then
  269.             .MsgBuffer = HeapAlloc(GetProcessHeap(), 0, 4 * (lBeforeSize + lAfterSize))
  270.             '--- fill new buffer: part 1
  271.             If lBeforeSize > 0 Then
  272.                 CopyMemory .MsgBuffer, VarPtr(m_aBeforeMsgs(0)), 4 * lBeforeSize
  273.             End If
  274.             '--- fill new buffer: part 2
  275.             If lAfterSize > 0 Then
  276.                 CopyMemory .MsgBuffer + 4 * lBeforeSize, VarPtr(m_aAfterMsgs(0)), 4 * lAfterSize
  277.             End If
  278.         End If
  279.         .BeforeBufferSize = lBeforeSize
  280.         .AfterBufferSize = lAfterSize
  281.     End With
  282.     '--- refresh heap chunk
  283.     CopyMemory ThunkAddress, VarPtr(m_uThunk), Len(m_uThunk)
  284.     '--- success
  285.     pvRefreshMsgsBuffer = True
  286. End Function
  287. Private Function pvGetProcAddr(sModule As String, sFunction As String) As Long
  288.     pvGetProcAddr = GetProcAddress(GetModuleHandle(sModule), sFunction)
  289. End Function
  290. Private Property Get IsNT() As Boolean
  291.     Dim uVer            As OSVERSIONINFO
  292.     uVer.dwOSVersionInfoSize = Len(uVer)
  293.     If GetVersionEx(uVer) Then IsNT = uVer.dwPlatformID = VER_PLATFORM_WIN32_NT
  294. End Property
  295.  
  296. '//////////////////////////////////////////////////////////////////////////////
  297. '//// CLASS EVENTS
  298. '//////////////////////////////////////////////////////////////////////////////
  299. Private Sub Class_Initialize()
  300.     Dim lIdx            As Long
  301.     Dim vOpcode         As Variant
  302.     
  303.     '--- extract code
  304.     For Each vOpcode In Split(STR_ASM_OPCODES)
  305.         m_uThunk.Code(lIdx) = vOpcode
  306.         lIdx = lIdx + 1
  307.     Next
  308.     '--- create "empty" arrays
  309.     ReDim m_aBeforeMsgs(-1 To -1)
  310.     ReDim m_aAfterMsgs(-1 To -1)
  311. End Sub
  312. Private Sub Class_Terminate()
  313.     On Error Resume Next
  314.     UnSubclass
  315. End Sub
  316.